<template>
	<view class="wrap area-b">
		<u-navbar zIndex="100" :title="pageTitle" :title-width="630">
			<view @tap="ingroupJump(`/pages/group/info?id=${id}`)" slot="right" class="u-m-r-30">
				<u-icon name="more-dot-fill" size="34"></u-icon>
			</view>
		</u-navbar>
		<scroll-view 
			id="scrollView"
			class="body" 
			scroll-y
			:lower-threshold="scroll.threshold"
			:scroll-top="scroll.top"
			:scroll-into-view="scroll.into"
			:scroll-with-animation="scroll.animation"
			@tap="foot=''"
			@scroll="onScroll"
			@scrolltolower="onToupper"
		>
			<view id="messageList" class="messageList">
				<view class="msg-info" v-if="nomore"><text class="txt">没有更多了</text></view>
				<msg-bable 
					v-for="(item,index) in messages" 
					:msg="item"
					:key="item.id"
					:chatType="conversation.type"
					:showRead="groupInfo.isShowRead"
					@tapMsg="tapMsg(item)"
					@tapAvatar="tapAvatar(item)"
					@longAvatar="longAvatar"
					@menu="menuMsg(item)"
					@appear= "onMsgAppear(item,$event)"
				></msg-bable>
				<!-- :showMine="groupInfo.isShowRedMine" -->
				<view class="scroll-foot"></view>
			</view>
			
		</scroll-view>
		<view class="mention-tip" @tap="tapMentionTip" :class="{show:mentionTip.show}">
			<text class="iconfont icon-upwards u-font-36 u-m-r-6"></text>
			<text class="u-font-28">{{mentionTip.isAll?'[@所有人]':'[有人@你]'}}</text>
		</view>
		<view class="foot" :class="{open:foot,disable:!canSend}">
			<view class="tools">
				<!-- #ifdef APP-PLUS -->
				<view class="sound item u-font-60">
					<text :class="mike.show?'cuIcon-keyboard':'cuIcon-sound'" @tap="openMike"></text>
				</view>
				<!-- #endif -->
				<view v-if="!canSend" class="main item u-text-center">
					<text>{{muteReason}}</text>
				</view>
				<view v-else class="main item">
					<textarea 
						:value="text" 
						:focus="input.focus"
						:cursor="input.cursor"
						maxlength="300" 
						:show-confirm-bar="false" 
						auto-height 
						:cursor-spacing="14"
						class="input" 
						@focus="inputFocus" 
						@blur="inputBlur" 
						@input="onInput"
					/>
				</view>
				<view class="face item u-font-60">
					<text class="cuIcon-emoji" @tap="changeFoot('faces')"></text>
				</view>
				<view class="send item">
					<!-- #ifdef APP -->
					<button class="cu-btn bg-green shadow" v-show="text" @touchend.prevent="sendText">发送</button>
					<!-- #endif -->
					<!-- #ifndef APP -->
					<button class="cu-btn bg-green shadow" v-show="text" @tap="sendText">发送</button>
					<!-- #endif -->
					<view class="u-font-60" v-show="!text" @tap="changeFoot('menus')">
						<text class="cuIcon-roundadd" />
					</view>
				</view>
			</view>
			<view class="content">
				<view class="menus" v-show="foot=='menus'">
					<view class="menus-box">
						<view class="menu-item">
							<view class="menu" @tap="chooseImg">
								<view class="info u-font-50">
									<text class="cuIcon-picfill"></text>
								</view>
								<text class="title">图片</text>
							</view>
						</view>
						<view class="menu-item">
							<view class="menu" @tap="chooseVideo">
								<view class="info u-font-50">
									<text class="cuIcon-videofill"></text>
								</view>
								<text class="title">视频</text>
							</view>
						</view>
						<view class="menu-item" v-if="canManage||groupInfo.isSendFile">
							<view class="menu" @tap="sendFile">
								<view class="info u-font-50">
									<text class="iconfont icon-folderfill"></text>
								</view>
								<text class="title">文件</text>
							</view>
						</view>
						<!-- <view class="menu-item" v-if="!examine">
							<view class="menu" @tap="sendRed">
								<view class="info u-font-50">
									<text class="iconfont icon-redfill"></text>
								</view>
								<text class="title">红包</text>
							</view>
						</view> -->
						<view class="menu-item" v-if="canManage||groupInfo.isSendCard">
							<view class="menu" @tap="sendUserCard">
								<view class="info u-font-50">
									<text class="iconfont icon-userfill"></text>
								</view>
								<text class="title">名片</text>
							</view>
						</view>
						<view class="menu-item" v-if="canManage||groupInfo.isSendCard">
							<view class="menu" @tap="sendGroupCard">
								<view class="info u-font-50">
									<text class="iconfont icon-groupfill"></text>
								</view>
								<text class="title">群名片</text>
							</view>
						</view>
						<view class="menu-item" v-if="(!examine)&&groupInfo.isShowRedMine">
							<view class="menu" @tap="sendBomb">
								<view class="info u-font-50">
									<text class="iconfont icon-bomb"></text>
								</view>
								<text class="title">扫雷红包</text>
							</view>
						</view>
					</view>
				</view>
				<view class="faces-box" v-show="foot=='faces'">
					<view class="faces-class">
						<view class="item" :class="{cur:faceType=='emoji'}" @tap="faceType='emoji'">
							<text class="cuIcon-emoji"></text>
						</view>
						<view class="item" :class="{cur:faceType=='custom'}" @tap="faceType='custom'">
							<text class="iconfont icon-heart"></text>
						</view>
					</view>
					<scroll-view v-show="faceType=='custom'" style="height: 310rpx;" scroll-y @scrolltolower="moreFace">
						<view class="faces">
							<view class="item" @tap="jumpTo(`/pages/face/my`)">
								<view class="add">
									<text class="cuIcon-add"></text>
								</view>
							</view>
							<view class="item" v-for="(item,idx) in faces.list" :key="item.id">
								<image class="img" :src="item.imgUrl" mode="aspectFit" @tap="sendFace(item)" />
							</view>
						</view>
					</scroll-view>
					<scroll-view v-show="faceType=='emoji'" style="height: 310rpx;" scroll-y>
						<view class="emojis">
							<view class="emoji" v-for="item in emojiList" :key="item.name">
								<image :src="item.url" @tap="chooseEmoji(item)" />
							</view>
						</view>
					</scroll-view>
				</view>
			</view>
		</view>
		<view class="mike-wrap area-b" :class="{show:mike.show}">
			<view class="mask" :class="{running:mike.running}" @tap="hideMike">
				
			</view>
			<view class="mike-box">
				<view class="mike-tip">
					{{mike.running?`松开即可发送，上划取消 ${mike.second}″`:'按住说话'}}
				</view>
				<view 
					@touchstart="voiceStart" 
					@touchmove.stop="voiceMove"
					@touchend="voiceEnd" 
					class="mike-circle cuIcon-voicefill"
					:class="{running:mike.running,cancel:mike.cancel}"
				>
				</view>
			</view>
		</view>
		<u-modal v-model="ask.show" :content="ask.content" @confirm="askConfirm" @cancel="askCancel" show-cancel-button></u-modal>
		<u-popup v-model="menuSheet.show" mode="center" border-radius="10">
			<view class="menuSheet">
				<view class="menu-opt" v-for="(item,index) in menuSheet.list" :key="index" @tap="askConfirm(item)">
					{{item.label}}
				</view>
			</view>
		</u-popup>
		<remind-picker :groupId="id" :canAll="canManage" ref="remindPicker" @confirm="onRemind"></remind-picker>
		<red-pop ref="redPop"></red-pop>
		<!-- <real-dialog v-model="realAsk.show"></real-dialog> -->
		<!-- #ifdef H5 -->
		<view class="video-player" @tap.self="vPlayer.show=false" v-if="vPlayer.show">
			<video class="video" id='vPlayer' :src="vPlayer.src" autoplay></video>
		</view>
		<!-- #endif -->
	</view>
</template>

<script>
	// #ifdef APP-PLUS
	import permission from "@/utils/permission.js"
	const lemonjkFileSelect = uni.requireNativePlugin('lemonjk-FileSelect');
	// #endif
	import {toast,jumpTo, copy, delay} from "@/utils/util.js"
	import {v4 as uuv4} from 'uuid'
	import {
		mapState,
		mapMutations,
		mapActions,
		mapGetters
	} from 'vuex';
	import chat, {
		msgTypes,
		dictateTypes
	} from "@/IM/index.js"
	import {Enum as authEnum,hasAuth} from "@/pages/group/authUtil.js"
	import * as fileUtil from '@/utils/file.js'
	import msgBable from "./msgBable/index.vue"
	import redPop from "@/pages/red/red-pop.vue"
	import remindPicker from "./remindPicker.vue"
	import realDialog from "@/components/dialogs/realname/index.vue"
	import * as redAPI from "@/api/red.js"
	import {TYPES as redTypes} from "@/api/red.js"
	import {addFace, getMyfaces} from "@/api/face.js"
	import * as sessionAPI from "@/api/session.js"
	import {getMyGroupAuth,fetchGroupInfo} from "@/api/addr.js"
	import {
		makeEmojiList
	} from '@/utils/emojiMap.js'
	import { getPool } from "@/IM/messagePool";
	import { ConversationType } from "@/entity/ConversationType";
	import { getMemberRole } from "@/api/group";
	import DC from "@/DC";
	// #ifdef APP-PLUS
	import { copyToPath, downToPath, pathByUrl } from "@/services/mediaService";
	const txVideoTool = uni.requireNativePlugin('TX-VideoTool');
	// #endif
	const recorderManager = uni.getRecorderManager();
	let bridge = null 
	export default {
		components:{
			msgBable,
			redPop,
			remindPicker,
			realDialog
		},
		data() {
			const systemInfo = uni.getSystemInfoSync()
			return {
				id: '', 
				groupInfo:{},
				power:{}, 
				emojiList:[],
				faceType:'emoji', 
				faces:{ 
					list:[],
					pageNo:1,
					pageSize:20,
					nomore:false,
					loading:false
				},
				scroll:{
					threshold:systemInfo.windowHeight*0.8,
					curTop:0,
					top:0,
					into:'',
					animation:false,
					infoot:true
				},
				monitors:[],
				
				messages:[], 
				loading:false, 
				nomore:false, 
				stamp:Date.now(), 
				input:{
					focus:false,
					cursor:0,
				},
				text: '', 
				
				foot: '', 
				mike:{
					show:false,
					running:false ,
					cancel:false, 
					startTime:0,
					startY:0, 
					timer:null,
					second:0,
					lastTime:0, 
				},
				mentionTip:{
					show:false,
					msgId:'',
					isAll:false
				},
				mentions:[], 
				mentCursor:-1, 
				ask:{
					show:false,
					content:'',
					confirm:'确认',
					cancel:'取消'
				},
				menuSheet:{
					show:false,
					list:[
						{
							label:'复制',
							fun:'copy'
						},
						{
							label:'撤回',
							fun:'recall'
						},
					]
				},
				realAsk:{
					show:false,
				},
				deposit:{ 
					list:[],
					finish:false
				},
				// #ifdef H5
				vPlayer:{
					ctx:null, 
					src:'',
					show:false 
				}
				// #endif
			};
		},
		computed:{
			...mapState('chat', {
				conversation({conversationMap}){
					return conversationMap[this.id]
				},
				gotReds({gotReds}){
					return gotReds
				}
			}),
			...mapGetters('user', ['userInfo','isReal']),
			...mapGetters('wallet', ['assets']),
			...mapGetters('system',['examine']),
			pageTitle(){
				let title = ''
				if(!this.conversation.name){
					title += '群聊'
				}else if(this.conversation.name.length<15){
					title += this.conversation.name
				}else{
					title += this.conversation.name.slice(0,15)+'...'
				}
				if(this.groupInfo&&this.groupInfo.userCount){
					title += `（${this.groupInfo.userCount}）`
				}
				return title
			},
			curUser(){
				return {
					avatarUrl:this.conversation.avatar,
					userName:this.conversation.name,
					userId:this.id
				}
			},
			systemInfo(){
				return getApp().globalData.systemInfo
			},
			canManage(){
				return !!this.power&&(this.power.vest=='群主'||this.power.vest=='管理员')
			},
			canSend(){
				if(this.power.vest=='群主'||this.power.vest=='管理员'){
					return true
				}
				if(this.power.rule===undefined||this.groupInfo.isSilent===undefined){
					return true
				}
				if(!this.groupInfo.isSilent&&hasAuth(this.power.rule,authEnum.send)){
					return true
				}
				return false
			},
			muteReason(){
				if(this.groupInfo.isSilent){
					return '全员禁言中'
				}
				if(!hasAuth(this.power.rule,authEnum.send)){
					return '您已被禁言'
				}
				return ''
			}
		},
		async onLoad({
			id
		}) {
			uni.$on('chat_receive',this.onChatReceive)
			uni.$on('custom_face_changed',this.resetFace)
			uni.$on('im_login_success',this.fetchNewMsg)
			uni.$on('clear_chat_history',this.clearMsg)
			this.id = id;
			
			this.messages = [...getPool(this.id)]
			this.resetFace()
			this.scrollBottom()
			if(this.conversation.mention){
				this.mentionTip.msgId = this.conversation.mention
				this.mentionTip.isAll = this.conversation.mentionAll
			}
			
			this.$nextTick(()=>{
				uni.setNavigationBarTitle({
					title: this.conversation.name
				})
			})
			
			await this.initGroupInfo()
			await this.setConversation({
				id,
				unread:0,
				mention:'',
				mentionAll:false
			})
			
			try{
				this.power = await getMyGroupAuth(this.id)
			}catch(e){
				this.power = {rule: 0,vest: ""}
				this.stamp = this.messages[0]?this.messages[0].createTime:0
				
				return 
			}
			this.activeConv()
			this.fetchMsg().then((list)=>{
				this.deposit.finish = true
				if(!list||!list.length){
					return []
				}
				this.messages.splice(0,this.messages.length,...list,...this.deposit.list)
				this.deposit.list=[]
				this.stamp = this.messages[0]?this.messages[0].createTime:this.stamp
				this.scrollBottom()
				this.saveHistory()
				this.listenMention()
			})
			delay(1000).then(()=>{
				this.emojiList = makeEmojiList()
			})
		},
		onUnload() {
			uni.$off('chat_receive',this.onChatReceive)
			uni.$off('custom_face_changed',this.resetFace)
			uni.$off('im_login_success',this.fetchNewMsg)
			uni.$off('clear_chat_history',this.clearMsg)
			this.activeConv()
			const pool = getPool(this.id)
			pool.splice(0,pool.length,...this.messages.slice(-10))
			this.monitors.forEach((item)=>{
				item.IO.disconnect()
			})
			this.footIO&&this.footIO.disconnect()
		},
		onReady() {
			// #ifdef H5
			this.vPlayer.ctx = uni.createVideoContext('vPlayer',this)
			// #endif
			const footIO = uni.createIntersectionObserver(this).relativeTo("#scrollView")
			footIO.observe('.scroll-foot',({intersectionRatio})=>{
				this.scroll.infoot = intersectionRatio>0
			})
			this.footIO = footIO
			recorderManager.onStart(()=>{
				console.log("开始录音了")
				this.mike.startTime = Date.now()
				this.mike.running = true
				this.mike.cancel = false
				this.mike.second = 0
				this.mike.timer = setInterval(()=>{
					this.mike.second ++
				},1000)
			})
			recorderManager.onStop(({
				tempFilePath
			}) => {
				try{
					const long = Date.now() - this.mike.startTime;
					if (this.mike.cancel) {
						return toast('取消录音')
					}
					if (long < 1000) {
						return toast('说话时间太短')
					}
					this.sendVoice(tempFilePath, long)
				}finally{
					this.mike.running = false
					this.mike.cancel = false
					this.mike.second = 0
					this.mike.startTime = 0
					clearInterval(this.mike.timer)
				}
			});
			recorderManager.onError(()=>{
				this.mike.running = false
				this.mike.cancel = false
				this.mike.second = 0
				this.mike.startTime = 0
				clearInterval(this.mike.timer)
				// #ifndef APP-PLUS
				if(this.systemInfo.platform=='ios'){
					if(!permission.judgeIosPermission('record')){
						new Promise((resolve,reject)=>{
							bridge={
								resolve,
								reject
							}
							this.openAsk('请打开麦克风权限',"去开启","拒绝")
						}).then(()=>{
							permission.gotoAppPermissionSetting()
						}).catch(()=>{
							console.log('拒绝打开')
						})
					}
				}
				// #endif
			})
		},
		methods:{
			jumpTo,
			...mapMutations('chat',['setChannel']),
			...mapActions('chat', ['sendMessage','saveHistory','setConversation','fetchConversation']),
			realGuard(){
				if(!this.isReal){
					this.realAsk.show = true
					throw new Error('请完成实名认证')
				}
			},
			clearMsg({id,time}){
				if(id!=this.id){
					return
				}
				this.messages.splice(0,this.messages.length)
			},
			onChatReceive(id,msg){
				if(this.id != id){
					return
				}
				this.setConversation({
					id,
					unread:0,
					mention:'',
					mentionAll:false
				})
				if(msg.msgType==msgTypes.RECALL){
					const idx = this.messages.findIndex((item)=>item.id==msg.extras.recallId)
					if(idx>=0){
						this.messages.splice(idx,1)
					}
				}
				this.messages.push(msg)
				if(!this.deposit.finish){
					this.deposit.list.push(msg)
				}
				if(this.scroll.infoot){
					this.scrollBottom()
				}
				chat.dictate({
					to:this.userInfo.userId,
					msgType:dictateTypes.readConv,
					content:'会话已读',
					extras:{
						id:this.id,
						type:ConversationType.Group
					}
				})
			},
			onScroll({detail:{scrollHeight,scrollTop}}){
				this.scroll.curTop = scrollTop
			},
			async onToupper(){
				const list = await this.moreMsg()
			},
			scrollBottom() { 
				this.scroll.top = this.scroll.top==0?0.1:0
				this.scroll.animation = false
			},
			async scrollToMsg(msgid){
				if(this.messages.some((item)=>item.id==msgid)){
					this.$nextTick(()=>{
						const query = uni.createSelectorQuery().in(this)
						query.select(`#scrollView`).boundingClientRect()
						query.select(`#msg_${msgid}`).boundingClientRect()
						query.exec(([body,msg])=>{
							const target = this.scroll.curTop - msg.top + body.top
							this.scroll.top = this.scroll.top==target?target+0.1:target
							this.scroll.animation = true
						})
					})
					return 
				}
				const list = await this.moreMsg() 
				if(!list||!list.length){
					throw new Error('未找到该消息')
				}else{
					return this.scrollToMsg(msgid)
				}
			},
			async tapMentionTip(){
				try{
					await this.scrollToMsg(this.mentionTip.msgId)
				}finally{
					this.mentionTip.show = false
					this.mentionTip.msgId = ''
				}
			},
			listenMention(){
				
				if(!this.mentionTip.msgId){
					return
				}
				
				if(!this.messages.some((item)=>item.id==this.mentionTip.msgId)){
					this.mentionTip.show = true
					return
				}
				
				const key = 'mention'
				if(this.monitors.some((item)=>item.key==key)){
					return
				}
				this.$nextTick(()=>{
					const IO = uni.createIntersectionObserver(this).relativeTo("#scrollView")
					const watch = {
						key,
						IO
					}
					this.monitors.push(watch)
					IO.observe(`#msg_${this.mentionTip.msgId}`,({intersectionRatio})=>{
						if(intersectionRatio>0){
							IO.disconnect() 
							this.monitors = this.monitors.filter((item)=>watch.key!=item.key) 
							this.mentionTip.msgId = ''
							this.mentionTip.show = false
						}else{
							this.mentionTip.show = true
						}
					})
					
				})
				
			},
			inputFocus() { 
				this.foot=""
			},
			inputBlur({detail:{cursor,value}}){
				this.input.focus = false
				this.input.cursor = cursor
				this.text = value
			},
			onInput({detail:{value,cursor}}){
				try{
					if(value.slice(cursor-1,cursor)=='@'&&this.text.slice(cursor-1,cursor)!='@'){
						this.mentCursor = cursor-1
						this.$refs.remindPicker.open()
						this.input.focus = false
					}
				}finally{
					this.text = value
					this.input.cursor = cursor
				}
			},
			onRemind(member){
				if(!this.mentions.some(item=>item.userId==member.userId)){
					this.mentions.push(member)
				}
				this.text = `${this.text.slice(0,this.mentCursor)}@${member.userName} ${this.text.slice(this.mentCursor+1)}`
				this.$refs.remindPicker.close()
				this.input.focus = true
			},
			changeFoot(name) { 
				this.foot = this.foot == name ? '' : name;
				this.scrollBottom()
			},
			chooseEmoji(item) { 
				this.text = this.text.slice(0,this.input.cursor)+item.name+this.text.slice(this.input.cursor)
				this.input.cursor += item.name.length
			},
			activeConv(){
				if(!this.power||!this.power.rule){
					return
				}
				sessionAPI.activeByTo(this.conversation.id,'群')
				chat.dictate({
					to:this.userInfo.userId,
					msgType:dictateTypes.readConv,
					content:'会话已读',
					extras:{
						id:this.id,
						type:ConversationType.Group
					}
				})
			},
			async resetFace(){
				this.faces.list = []
				this.faces.pageNo = 1
				this.faces.nomore = false
				await this.moreFace()
			},
			async moreFace(){
				if(this.faces.loading){
					throw new Error('正在请求中')
				}
				try{
					this.faces.loading = true
					if(this.faces.nomore){
						return []
					}
					const list = await getMyfaces(this.faces)
					if(!list||list.length<this.faces.pageSize){
						this.faces.nomore = true
					}else{
						this.faces.pageNo++
					}
					this.faces.list.push(...list)
					return list
				}finally{
					this.faces.loading = false
				}
			},
			
			ingroupJump(url){
				if(this.power&&this.power.rule){
					jumpTo(url)
				}
			},
			initGroupInfo(){
				this.groupInfo = DC.groupDB.getGroup(this.id)
				return this.groupInfo.fetchOrigin()
			},
			
			openMike(){
				this.foot = 'mike'
				this.mike.show = true
			},
			
			hideMike(){
				this.foot = ''
				this.mike.show = false
			},
			async voiceStart({
				changedTouches
			}) {
				const now = Date.now()
				if(now-this.mike.lastTime<2000){
					return
				}
				this.mike.lastTime = now
				console.log('触摸开始')
				const touche = changedTouches[0];
				this.mike.startY = touche.clientY
				
				if(this.systemInfo.platform=='android'){
					if(!permission.judgeAndroidPermission('RECORD')){
						const res = await permission.requestAndroidPermission('android.permission.RECORD_AUDIO')
						if(res!=1){
							new Promise((resolve,reject)=>{
								bridge={
									resolve,
									reject
								}
								this.openAsk('请打开麦克风权限',"去开启","拒绝")
							}).then(()=>{
								permission.gotoAppPermissionSetting()
							}).catch(()=>{
								console.log('拒绝打开')
							})
						}
						return
					}
				}
				// #ifndef H5
				recorderManager.start()
				// #endif
			},
			async voiceMove({
				changedTouches
			}) {
				const touche = changedTouches[0];
				if (this.mike.startY - touche.clientY > 50) {
					this.mike.cancel = true;
				} else {
					this.mike.cancel = false;
				}
			},
			async voiceEnd() {
				console.log('触摸结束')
				// #ifndef H5
				recorderManager.stop()
				// #endif
			},
			async fetchMsg(){
				if(this.fetchMsg.lock){
					throw new Error('正在请求中')
				}
				try{
					this.fetchMsg.lock = true
					const {
						data:{
							groups={},
						}={}
					} = await chat.getHistory({
						groupId:this.id,
						offset:0,
						count:50, 
						beginTime:this.conversation.clearTime,
						endTime:this.stamp-1 
					});
					const list = groups[this.id]||[]
					if(list.length<50){
						this.nomore = true 
					}
					list.reverse()
					// #ifdef APP-PLUS
					return list.map((message)=>{
						if(message.msgType == msgTypes.IMG){
							message.saveImg = ''
							const imgUrl = message.extras.imgUrl
							pathByUrl(imgUrl).then((path)=>{
								if(path){
									message.saveImg = path
								}else{
									downToPath(imgUrl).then((newPath)=>{
										message.saveImg = newPath
									})
								}
							})
						}
						if(message.msgType==msgTypes.VIDEO){
							message.saveVideo = ''
							message.saveThumb = ''
							const thumb = message.extras.thumb
							const videoUrl = message.extras.videoUrl
							pathByUrl(videoUrl).then((path)=>{
								if(path){
									message.saveVideo = path
								}else{
									downToPath(videoUrl).then((newPath)=>{
										message.saveVideo = newPath
									})
								}
							})
							pathByUrl(thumb).then((path)=>{
								if(path){
									message.saveThumb = path
								}else{
									downToPath(thumb).then((newPath)=>{
										message.saveThumb = newPath
									})
								}
							})
						}
						if(message.msgType == msgTypes.FACE&&!message.extras.type){
							message.saveImg = ''
							const imgUrl = message.extras.imgUrl
							pathByUrl(imgUrl).then((path)=>{
								if(path){
									message.saveImg = path
								}else{
									downToPath(imgUrl).then((newPath)=>{
										message.saveImg = newPath
									})
								}
							})
						}
						return message
					})
					// #endif
					// #ifndef APP-PLUS
					return list
					// #endif
				}finally{
					this.fetchMsg.lock = false
				}
			},
			async fetchNewMsg(){
				console.log('拉取新消息')
				if(this.fetchNewMsg.lock){
					throw new Error('正在请求中')
				}
				try{
					this.fetchNewMsg.lock = true
					const lastMsg = this.messages.slice(-1)[0]
					const beginTime = lastMsg?lastMsg.createTime+1:this.conversation.clearTime
					const {
						data:{
							groups={}
						}={}
					} = await chat.getHistory({
						groupId:this.id,
						offset:0,
						count:100, 
						beginTime,
						endTime: Date.now()
					});
					const list = groups[this.id]||[]
					list.reverse()
					if(!list.length){
						
					}else if(list.length>=100){
						
						this.resetMsg()
					}else if(list.length>0&&list.length<100){
						this.messages.push(...list.filter(item=>!this.messages.some(({id})=>item.id==id)))
						this.scrollBottom()
						this.saveHistory()
					}
					return list
				}finally{
					this.fetchNewMsg.lock = false
				}
			},
			
			async resetMsg(){
				this.stamp = Date.now()
				this.nomore = false
				this.messages.splice(0,this.messages.length)
				await this.moreMsg()
			},
			async moreMsg() {
				if(this.nomore||this.loading){
					return []
				}
				try{
					this.loading = true
					const list = await this.fetchMsg()
					this.stamp = list[0]?list[0].createTime:this.stamp
					this.messages.unshift(...list)
					this.listenMention()
					if(this.nomore){
						
					}
					return list
				}finally{
					this.loading = false
				}
			},
			
			async sendText() {
				if(!this.canSend){return}
				
				if(!this.text.trim()){
					this.text=''
					return
				}
				const at = this.mentions.filter((item)=>{
					return this.text.includes(`@${item.userName} `) 
				}).map(({userId})=>userId)
				const msg = chat.createMessage({
					chatType:1,
					groupId:this.id,
					content: this.text.trim(),
					msgType: msgTypes.TEXT,
					extras:{
						at:at.join(',')
					}
				})
				this.mentions = []
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.errMsg = ''
				try {
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.text = ''
					this.scrollBottom()
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				} catch (e) {
					console.log(e)
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{
				}
			},
			async chooseImg(){
				if(!this.canSend){return}
				const {
					tempFilePaths:[filePath],
					tempFiles:[file]
				} = await fileUtil.chooseImage({
					count: 1
				});
				this.sendImg({filePath,file})
			},
			
			async sendImg({filePath,file}) {
				const {width,height} = await fileUtil.getImageInfo({
					src:filePath
				})
				const imgInfo = {
					imgUrl: '',
					width,
					height
				}
				const msg = chat.createMessage({
					chatType:1,
					groupId:this.id,
					content: '[图片]',
					msgType: msgTypes.IMG,
					extras: imgInfo
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.localUrl = filePath;
				msg.progress = 0
				msg.errMsg = ''
				msg.saveImg =''
				try {
					this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					imgInfo.imgUrl = await fileUtil.uploadFile({
						file,
						onProgressUpdate:({progress})=>{
							msg.progress = progress
						}
					})
					// #ifdef APP-PLUS
					copyToPath(filePath,imgInfo.imgUrl).then((path)=>{
						msg.saveImg = path
					})
					// #endif
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				} catch (e) {
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{
					
				}
			},
			async sendVoice(file, long) { 
				if(!this.canSend){return}
				
				const voiceInfo = {
					voiceUrl: '',
					duration: long
				}
				const msg = chat.createMessage({
					chatType:1,
					groupId:this.id,
					extras: voiceInfo,
					content: '[语音]',
					msgType: msgTypes.AUDIO
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.errMsg = ''
				msg.localUrl = file;
				try {
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					voiceInfo.voiceUrl = await fileUtil.uploadFile({
						file
					})
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				} catch (e) {
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{

				}
			},
			async chooseVideo(){
				if(!this.canSend){return}
				
				const res = await fileUtil.chooseVideo({
					maxDuration: 60,
					camera: 'front'
				});
				this.sendVideo(res)
			},
			async sendVideo({tempFilePath,tempFile,width,height,duration}) { 
				const videoInfo = {
					videoUrl: '',
					thumb:'',
					width,
					height,
					duration
				}
				const msg = chat.createMessage({
					chatType:1,
					groupId:this.id,
					extras: videoInfo,
					content: '[视频]',
					msgType: msgTypes.VIDEO
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.progress = 0
				msg.errMsg = ''
				msg.localUrl = tempFilePath;
				msg.saveVideo = ''
				msg.saveThumb = ''
				try {
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					
					// #ifndef APP-PLUS
					videoInfo.videoUrl = await fileUtil.uploadFile({
						file: tempFile || tempFilePath,
						onProgressUpdate:({progress})=>{
							msg.progress = progress
						}
					})
					videoInfo.thumb = fileUtil.videoAdvance(videoInfo.videoUrl)
					// #endif
					// #ifdef APP-PLUS
					const thumb = await new Promise((resolve,reject)=>{
						txVideoTool.getVideoThumbnailImage({
							"videoPath": plus.io.convertLocalFileSystemURL(tempFilePath), 
							"saveImagePath": plus.io.convertLocalFileSystemURL("_doc/video_thumb/"), 
							"saveImageName": `thumb_${Date.now()}.png`,
							"second": 1
						}, ({imagePath}) => {
						   console.log(imagePath);
						   resolve(imagePath)
						});
						setTimeout(reject,3000)
					})
					videoInfo.videoUrl = await fileUtil.uploadFile({
						file: tempFile || tempFilePath,
						onProgressUpdate:({progress})=>{
							msg.progress = progress
						}
					})
					videoInfo.thumb = await await fileUtil.uploadFile({
						file:thumb,
						pre:'small/',
						key:videoInfo.videoUrl.slice(videoInfo.videoUrl.lastIndexOf('/')+1,videoInfo.videoUrl.lastIndexOf('.'))
					})
					copyToPath(thumb,videoInfo.thumb).then((path)=>{
						msg.saveThumb = path
					})
					copyToPath(tempFilePath,videoInfo.videoUrl).then((path)=>{
						msg.saveVideo = path
					})
					// #endif
					
					
					
					
					
					
					
					
					
					
					
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				} catch (e) {
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{

				}
			},
			async sendFile(){
				if(!this.canSend){return}
				const file = await new Promise((resolve,reject)=>{
					// #ifdef H5
					uni.chooseFile({
						count:1,
						success({tempFilePaths:[filePath],tempFiles:[file]}){
							resolve(file)
						},
						fail:reject
					})
					// #endif
					// #ifdef APP-PLUS
					lemonjkFileSelect.showPicker({
					    mimeType: "*/*",
					    utisType:"public.data",
					    }, 
						({code,detail,files:[file]})=>{
							if(code=='0'){
								return resolve({
									name:file.fileName,
									size:file.fileSize,
									path:file.filePath
								})
							}
							if(code=='1004'){
								return console.log(detail)
							}
							reject(new Error(detail))
						}
					)
					// #endif
				})
				console.log(file)
				if(/\.{1}(jpg|jpeg|png|gif)$/i.test(file.name)){
					return this.sendImg({filePath:file.path,file})
				}
				if(/\.{1}(mp4|rmvb|avi|wmv|flv|mkv|webm|mov)$/i.test(file.name)){
					const videoInfo = await new Promise((resolve,reject)=>{
						uni.getVideoInfo({
							src:file.path,
							success:resolve,
							fail:reject
						})
					})
					return this.sendVideo({...videoInfo,tempFilePath:file.path,tempFile:file})
				}
				const fileInfo ={
					fileUrl:'',
					name:file.name,
					size:file.size
				}
				const msg = chat.createMessage({
					chatType:1,
					groupId: this.id,
					extras: fileInfo,
					content: `[文件]`,
					msgType: msgTypes.FILE
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.progress = 0
				msg.errMsg = ''
				try{
					this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					fileInfo.fileUrl = await fileUtil.uploadFile({
						file,
						onProgressUpdate:({progress})=>{
							msg.progress = progress
						}
					})
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				}catch(e){
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}
			},
			async sendRed(){
				if(!this.canSend){return}
				if(!this.canManage&&!this.groupInfo.isSendRedPacket){
					return toast('群主开启了只允许管理员发送')
				}
				
				const redInfo = await new Promise((resolve,reject)=>{
					uni.$off('redCreated')
					uni.$once('redCreated',resolve)
					uni.navigateTo({
						url:`/pages/red/create?bid=${this.id}&btype=群`
					})
				})
				const msg = chat.createMessage({
					chatType:1,
					groupId: this.id,
					extras: redInfo,
					content: '[红包]',
					msgType: msgTypes.RED
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.errMsg = ''
				
				try{
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				}catch(e){
					console.log(e)
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{

				}
			},
			async sendBomb(){
				if(!this.canSend){return}
				
				const redInfo = await new Promise((resolve,reject)=>{
					uni.$off('bombCreated')
					uni.$once('bombCreated',resolve)
					uni.navigateTo({
						url:`/pages/red/bomb?bid=${this.id}&btype=群`
					})
				})
				const msg = chat.createMessage({
					chatType:1,
					groupId: this.id,
					extras: redInfo,
					content: '[红包]',
					msgType: msgTypes.RED
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.errMsg = ''
				
				try{
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				}catch(e){
					console.log(e)
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{
				}
			},
			async sendFace(face){
				if(!this.canSend){return}
				const msg = chat.createMessage({
					chatType:1,
					groupId:this.id,
					content: '[表情]',
					msgType: msgTypes.FACE,
					extras: face
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.errMsg = ''
				msg.run = true
				try {
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				} catch (e) {
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{
				}
			},
			async sendUserCard(){ 
				if(!this.canSend){return}
				
				const friend = await new Promise((resolve,reject)=>{
					uni.navigateTo({
						url:'/pages/friend/choose',
						events:{
							choose:resolve
						},
						fail:reject
					})
				})
				const msg = chat.createMessage({
					chatType:ConversationType.Group,
					groupId: this.id,
					content: '[个人名片]',
					msgType: msgTypes.CARD,
					extras: {
						type:ConversationType.Single,
						id:friend.userId,
						avatar:friend.avatarUrl,
						name:friend.userName
					}
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.errMsg = ''
				try {
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					delay(500).then(()=>{
						this.scrollBottom()
					})
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				} catch (e) {
					console.log(e)
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{
				}
			},
			async sendGroupCard(){ 
				if(!this.canSend){return}
				
				const group = await new Promise((resolve,reject)=>{
					uni.navigateTo({
						url:'/pages/group/choose',
						events:{
							choose:resolve
						},
						fail:reject
					})
				})
				const msg = chat.createMessage({
					chatType:ConversationType.Group,
					groupId:this.id,
					content: '[群名片]',
					msgType: msgTypes.CARD,
					extras: {
						type:ConversationType.Group,
						id:group.id,
						avatar:group.avatar,
						name:group.name
					}
				})
				msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
				msg.avatar = this.userInfo.avatarUrl
				msg.nick = this.userInfo.userName
				msg.status = 'loading';
				msg.errMsg = ''
				try {
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					delay(500).then(()=>{
						this.scrollBottom()
					})
					await chat.send(msg)
					msg.status = 'success';
					this.saveHistory()
				} catch (e) {
					console.log(e)
					msg.status = 'error';
					msg.errMsg = e.message
					toast(e.message)
				}finally{
				}
			},
			async videoCall() { 
				if(!this.canSend){return}
				
				try{
					if(this.videoCall.lock){
						throw new Error('请勿重复点击')
					}
					const roomId = uuv4();
					const isAudio = false
					const msg = chat.createMessage({
						chatType:1,
						groupId:this.id,
						content: '[视频通话]',
						msgType: msgTypes.CALL,
						extras:{
							type:'video',
							duration:0
						}
					})
					msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
					msg.avatar = this.userInfo.avatarUrl
					msg.nick = this.userInfo.userName
					msg.errMsg = ''
					msg.status = 'loading'
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					this.setChannel({
						channelId:roomId,
						isAudio,
						msg,
						userId:this.id,
						userName:this.curUser.userName,
						avatar:this.curUser.avatarUrl
					})
					await new Promise((resolve,reject)=>{
						uni.navigateTo({
							url:`/pages/room/call?to=${this.id}`,
							success:resolve,
							fail:reject
						})
					})
				}finally{
					this.videoCall.lock=false
				}
			},
			async audioCall(cost) { 
				if(!this.canSend){return}
				
				try{
					if(this.audioCall.lock){
						throw new Error('请勿重复点击')
					}
					const roomId = uuv4();
					const isAudio = true
					const msg = chat.createMessage({
						chatType:1,
						groupId:this.id,
						content: '[语音通话]',
						msgType: msgTypes.CALL,
						extras:{
							type:'voice',
							duration:0
						}
					})
					msg.readBody = {readCount:0,unreadCount:this.groupInfo.userCount-1}
					msg.avatar = this.userInfo.avatarUrl
					msg.nick = this.userInfo.userName
					msg.errMsg = ''
					msg.status = 'loading'
					await this.sendMessage({
						message: msg,
						id: this.id
					})
					this.messages.push(msg)
					this.scrollBottom()
					this.setChannel({
						channelId:roomId,
						isAudio,
						msg,
						userId:this.id,
						userName:this.curUser.userName,
						avatar:this.curUser.avatarUrl
					})
					await new Promise((resolve,reject)=>{
						uni.navigateTo({
							url:`/pages/room/call?to=${this.id}`,
							success:resolve,
							fail:reject
						})
					})
				}finally{
					this.audioCall.lock=false
				}
			},
			tapAvatar(msg){
				if(this.groupInfo.isAddFriend||this.canManage){
					return jumpTo(`/pages/user/info?id=${msg.from}`)
				}else{
					getMemberRole({id:this.id,uid:msg.from}).then(({vest})=>{
						if(vest=='群主'||vest=='管理员'){
							jumpTo(`/pages/user/info?id=${msg.from}`)
						}
					})
				}
			},
			longAvatar(msg,master){
				if(!hasAuth(this.power.rule,authEnum.send)){
					return
				}
				const member = {
					userName:master.userName||msg.nick,
					userId:msg.from
				}
				if(member.userId==this.userInfo.userId){
					return
				}
				if(!this.mentions.some(item=>item.userId==member.userId)){
					this.mentions.push(member)
				}
				uni.getSelectedTextRange({
					success:({start,end})=>{
						this.text = this.text.slice(0,end)+`@${member.userName} `+this.text.slice(end)
					},
					fail:(e) =>{
						this.text = this.text+`@${member.userName} `
					}
				})
				
				
				
			},
			copyMsg(msg){
				copy(msg.content)
			},
			async recallMsg(msg){ 
				try{
					const param = {msgId:msg.id,to:this.id,chatType:'群'}
					await chat.recall(param)
					
					
					
					
					
					
					
					
					
					
					
					
					
					
					
					
					
				}catch(e){
					toast(e.message)
				}
			},
			async relayMsg(msg){
				uni.navigateTo({
					url:'/pages/room/relay',
					events:{
						succeed:()=>{
							delay(500).then(()=>{
								uni.showToast({
									title:'转发成功',
									icon:'success'
								})
							})
						}
					},
					success:({eventChannel})=>{
						eventChannel.emit('init',msg)
					}
				})
			},
			async addFace({extras:{imgHeight,imgUrl,imgWidth}}){
				await addFace({
					imgUrl,
					imgHeight,
					imgWidth
				})
				uni.showToast({
					title:'添加成功'
				})
				this.resetFace()
			},
			async menuMsg(msg){
				console.log(msg)
				const list = []
				if(msg.msgType==msgTypes.TEXT){
					list.push({
						label:'复制',
						fun:'copyMsg'
					})
				}
				if(msg.msgType==msgTypes.FACE){
					list.push({
						label:'添加表情',
						fun:'addFace'
					})
				}
				
				if([msgTypes.IMG,msgTypes.VIDEO,msgTypes.TEXT,msgTypes.FACE].includes(msg.msgType)){
					list.push({
						label:'转发',
						fun:'relay'
					})
				}
				
				if(msg.msgType!=msgTypes.RED&&((this.groupInfo.isRecallMsg&&msg.from==this.userInfo.userId)||this.canManage)){
					list.push({
						label:'撤回',
						fun:'recallMsg'
					})
				}
				if(!list.length){
					return 
				}
				const opt = await new Promise((resolve,reject)=>{
					this.menuSheet.list = list
					this.menuSheet.show = true
					bridge = {
						resolve,
						reject
					}
				})
				this.menuSheet.show = false
				if(opt.fun=='recallMsg'){
					this.recallMsg(msg)
				}
				if(opt.fun=='copyMsg'){
					this.copyMsg(msg)
				}
				if(opt.fun=='relay'){
					this.relayMsg(msg)
				}
				if(opt.fun=='addFace'){
					this.addFace(msg)
				}
			},
			tapMsg(msg){ 
				
				if(msg.msgType==msgTypes.TEXT||msgTypes.AUDIO==msg.msgType){
					return
				}
				if(msg.msgType==msgTypes.RED){
					return this.grabRed(msg)
				}
				if(msg.msgType==msgTypes.CARD){
					return this.handleCard(msg)
				}
				if(msg.msgType==msgTypes.NOTICE){
					return this.handleNotice(msg.extras)
				}
				// #ifdef H5
				
					if(msg.msgType==msgTypes.IMG){
						uni.previewImage({
							current:msg.localUrl||msg.extras.imgUrl,
							urls:this.messages.reduce((r,n)=>{
								if(n.msgType==msgTypes.IMG){
									r.push(n.localUrl||n.extras.imgUrl)
								}
								return r
							},[])
						})
					}
					if(msg.msgType==msgTypes.VIDEO){
						this.vPlayer.src = msg.extras.videoUrl
						this.vPlayer.show = true
						
						
						
					}
					
				// #endif
				
				// #ifdef APP-PLUS
					if(msg.msgType==msgTypes.IMG){
						uni.previewImage({
							current:msg.localUrl||msg.saveImg||msg.extras.imgUrl,
							urls:this.messages.reduce((r,n)=>{
								if(n.msgType==msgTypes.IMG){
									r.push(n.localUrl||n.saveImg||n.extras.imgUrl)
								}
								return r
							},[])
						})
					}
					if(msg.msgType==msgTypes.VIDEO){
						jumpTo(`/pages/preVideo/preVideo?src=${msg.localUrl||msg.saveVideo||msg.extras.videoUrl}`)
						
					}
				// #endif
				
				// #ifdef MP-WEIXIN
					wx.previewMedia(
						this.messages.reduce((r,n)=>{
							if(n.msgType==msgTypes.IMG){
								if(n.extras.imgUrl==msg.extras.imgUrl){
									r.current=r.sources.length
								}
								r.sources.push({
									url:n.extras.imgUrl,
									type:'image'
								})
							}
							if(n.msgType==msgTypes.VIDEO){
								if(n.extras.videoUrl==msg.extras.videoUrl){
									r.current=r.sources.length
								}
								r.sources.push({
									url:n.extras.videoUrl,
									type:'video',
									poster:n.extras.thumb
								})
							}
							return r
						},{sources:[],current:0})
					)
				// #endif
			},
			grabRed(msg){
				if(this.gotReds.some(item=>item==msg.extras.id)){
					return uni.navigateTo({
						url:`/pages/red/result?id=${msg.extras.id}`
					})
				}
				if(Date.now()-msg.createTime>1000*60*60*24){
					return this.$refs.redPop.show({
						id:msg.extras.id,
						avatar:msg.avatar,
						title:`${msg.nick}的红包`,
						greet:'红包已失效，如已领取可查看领取详情',
						canDetail:true
					})
				}
				this.$refs.redPop.grab({
					avatar:msg.avatar, 
					userName:msg.nick,
					...msg.extras
				})
			},
			onMsgAppear(msg,scrap){
				chat.read(msg).then(()=>{
					scrap()
					if(msg.readBody&&msg.readBody.unreadCount>0){
						msg.readBody.unreadCount--
					}
				})
			},
			handleCard({extras,from}){
				if(extras.type==ConversationType.Group){
					jumpTo(`/pages/group/facade?id=${extras.id}&from=${from}`)
				}else if(extras.type==ConversationType.Single){
					jumpTo(`/pages/user/info?id=${extras.id}`)
				}
			},
			handleNotice(notice){
				jumpTo(`/pages/group/notice/detail?id=${notice.id}`)
			},
			openAsk(content,confirm,cancel){
				this.ask.content = content
				this.ask.confirm = confirm
				this.ask.cancel = cancel
				this.ask.show=true
			},
			askConfirm(e){
				bridge&&bridge.resolve&&bridge.resolve(e)
			},
			askCancel(e){
				bridge&&bridge.reject&&bridge.reject(e)
			}
		}
	}
</script>
<style>
	page{
		background-color: #F5F5F5;
	}
</style>
<style lang="scss" scoped>
	.wrap{
		display: flex;
		flex-direction: column;
		height: calc(100vh - var(--window-top));
	}
	.body{
		flex: 1;
		height: 100rpx;
		background-color: #F5F6F7;
		transform: rotateX(180deg);
		.messageList{
			min-height: 100%;
			transform: rotateX(180deg);
		}
		.scroll-foot{
			padding-bottom: 1rpx;
		}
	}
	.msg-info{
		padding: 20rpx 0;
		text-align:center;
		.txt{
			padding: 6rpx 10rpx;
			background-color: rgba($color: #000000, $alpha: 0.2);
			color: #FFFFFF;
			font-size: 24rpx;
			border-radius: 10rpx;
		}
	}
	.mention-tip{
		position: fixed;
		right: 0;
		top: 15vh;
		padding: 14rpx 30rpx 14rpx 20rpx;
		border-radius: 100rpx 0 0 100rpx;
		transform: translateX(200%);
		transition: 300ms ease-out;
		box-shadow: 0 0 30rpx 0 rgba($color: #666666, $alpha: 0.2);
		background-color: #ffffff;
		color:#0081ff;
		display: flex;
		align-items: center;
		&.show{
			transform: translateX(0%);
		}
	}
	
	.foot {
		position: relative;
		z-index: 100;
		box-shadow: 0 -0.5px 3px rgba(0, 0, 0, 0.1);
		background-color: #ffffff;
		color: #333333;
		&.disable{
			.tools{
				pointer-events: none;
			}
			.content{
				pointer-events: none;
			}
		}
		.tools {
			box-sizing: border-box;
			min-height: 100rpx;
			padding: 10rpx;
			display: flex;
			align-items: flex-end;
			justify-content: space-between;
			outline: 2rpx solid #e7e7e7;
	
			.item {
				margin: auto 10rpx;
			}
	
			.main {
				border-radius: 10rpx;
				flex: 1;
				background-color: #F5F5F5;
				max-height: 200rpx;
				overflow: scroll;
				padding: 14rpx 20rpx;
				.input {
					width: 100%;
				}
			}
	
			.send {
				display: flex;
				align-items: center;
			}
		}
	
		&.open {
			.content {
				height: 400rpx;
			}
		}
	
		.content {
			height: 0;
		}
	
		.menus {
			width: 750rpx;
			height: 400rpx;
			.swiper{
				width: 100%;
				height: 100%;
			}
			.menus-box{
				display: flex;
				flex-wrap: wrap;
			}
			
			.menu-item {
				flex-shrink: 0;
				width: 25%;
				height: 190rpx;
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
				.menu {
					display: flex;
					flex-direction: column;
					align-items: center;
	
					.info {
						width: 100rpx;
						height: 100rpx;
						background-color: #F5F5F5;
						display: flex;
						justify-content: center;
						align-items: center;
						border-radius: 20rpx;
						margin-bottom: 10rpx;
					}
					.img-icon{
						width: 50rpx;
						height: 50rpx;
					}
				}
	
			}
		}
		.faces-box{
			.faces-class{
				display: flex;
				align-items: center;
				height: 90rpx;
				
				.item{
					width: 70rpx;
					height: 70rpx;
					border-radius: 10rpx;
					text-align: center;
					line-height: 70rpx;
					font-size: 46rpx;
					margin: 30rpx;
					&+.item{
						margin-left: 0;
					}
					&.cur{
						background-color: #F5F5F5;
					}
				}
			}
			.emojis{
				display: grid;
				grid-template-columns: repeat(8, 1fr);
				.emoji {
					display: flex;
					justify-content: center;
					margin: 10rpx 0;
				
					image {
						width: 60rpx;
						height: 60rpx;
					}
				}
			}
			.faces{
				display: flex;
				flex-wrap: wrap;
				padding: 10rpx 30rpx;
				.item{
					width: 122rpx;
					height: 122rpx;
					margin-right: 20rpx;
					margin-bottom: 20rpx;
					&:nth-of-type(5n){
						margin-right: 0;
					}
				}
				.add{
					font-size: 90rpx;
					width: 100%;
					height: 100%;
					display: flex;
					align-items: center;
					justify-content: center;
					border: 2rpx dashed #666666;
					color: #666666;
					border-radius: 14rpx;
				}
				.img{
					width: 100%;
					height: 100%;
				}
			}
		}
	}
	.video-player{
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba($color: #000000, $alpha: 0.6);
		display: flex;
		flex-direction: column;
		justify-content: center;
		.video{
			width: 750rpx;
		}
	}
	.menuSheet{
		width: 500rpx;
		.menu-opt{
			padding: 30rpx 40rpx;
			font-size: 32rpx;
			&+.menu-opt{
				border: 1rpx solid #F5F5F5;
			}
		}
	}
	.mike-wrap{
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 101;
		display: flex;
		flex-direction: column;
		transform: translateY(200%);
		&.show{
			transform: translateY(0%);
			.mike-box{
				transform: translateY(0%);
			}
		}
		.mask{
			flex: 1;
			&.running{
				background-color: rgba($color: #000000, $alpha: 0.2);
			}
		}
		.mike-box{
			height: 400rpx;
			background-color: #FFFFFF;
			transform: translateY(100%);
			transition: transform 300ms ease-out;
			display: flex;
			justify-content: center;
			align-items: center;
			position: relative;
		}
		.mike-tip{
			position: absolute;
			top: 30rpx;
			left: 50%;
			transform: translateX(-50%);
			font-size: 28rpx;
			color: #999999;
		}
		.mike-circle{
			width: 200rpx;
			height: 200rpx;
			background-color: #F5F5F5;
			border-radius: 50%;
			line-height: 200rpx;
			text-align: center;
			font-size: 100rpx;
			color: #0081ff;
			&.running{
				background-color: #0081ff;
				color: #FFFFFF;
			}
			&.cancel{
				background-color: #e54d42;
				color: #FFFFFF;
			}
		}
	}
</style>
